package svgs

import (
	"errors"
	"image/color"

	svg "github.com/ajstarks/svgo"
	"github.com/boombuler/barcode"
)

var errNotQR = errors.New("can not write to SVG: Not a QR code")

// QrSVG holds the data related to the size, location,
// and block size of the QR Code. Holds unexported fields.
type QrSVG struct {
	qr        barcode.Barcode
	qrWidth   int
	blockSize int
	startingX int
	startingY int
}

// NewQrSVG contructs a QrSVG struct. It takes a QR Code in the form
// of barcode.Barcode and sets the "pixel" or block size of QR Code in
// the SVG file.
func NewQrSVG(qr barcode.Barcode, blockSize int) QrSVG {
	return QrSVG{
		qr:        qr,
		qrWidth:   qr.Bounds().Max.X,
		blockSize: blockSize,
		startingX: 0,
		startingY: 0,
	}
}

// WriteQrSVG writes the QR Code to SVG.
func (qs *QrSVG) WriteQrSVG(elem *svg.SVG) error {
	if qs.qr.Metadata().CodeKind != "QR Code" {
		return errNotQR
	}

	rects := NewRects()

	for x := 0; x < qs.qrWidth; x++ {
		for y := 0; y < qs.qrWidth; y++ {
			if qs.qr.At(x, y) == color.Black {
				rects.Add(&Rect{X: x, Y: y, W: 1, H: 1})
			}
		}
	}
	// 压缩
	for _, r := range rects.Compress() {
		elem.Rect(
			r.X*qs.blockSize+qs.startingX,
			r.Y*qs.blockSize+qs.startingY,
			r.W*qs.blockSize,
			r.H*qs.blockSize,
			"fill=\"black\"",
		)
	}

	return nil
}

// SetStartPoint sets the top left start point of QR Code.
// This takes an X and Y value and then adds four white "blocks"
// to create the "quiet zone" around the QR Code.
func (qs *QrSVG) SetStartPoint(x, y int) {
	qs.startingX = x + qs.blockSize
	qs.startingY = y + qs.blockSize
}

const two = 2

// StartQrSVG creates a start for writing an SVG file that
// only contains a barcode. This is similar to the svg.Start() method.
// StartQrSVG should only be used if you only want to write a QR code
// to the SVG. Otherwise use the regular svg.Start() method to start your
// SVG file.
func (qs *QrSVG) StartQrSVG(s *svg.SVG) {
	width := (qs.qrWidth * qs.blockSize) + (qs.blockSize * two)
	qs.SetStartPoint(0, 0)
	s.Start(width, width)
	// 底色
	s.Rect(0, 0, width, width, "fill=\"white\"")
}
